home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / New System Software Extensions / QuickDraw™ 3D 1.0 / Samples / SampleCode / Tumbler and Podium / Tumbler_drag.c < prev    next >
Encoding:
Text File  |  1995-06-08  |  24.4 KB  |  817 lines  |  [TEXT/MPS ]

  1. // Tumbler_drag.c
  2. //
  3. // Dragging routines. The code in this file implements the geometry
  4. // dragging features of this program.  The last function in this file,
  5. // DoDragObjects is called when a mouseDown is detected in the hilite region
  6. // of the current object.
  7. //  
  8. // Here's some background from Nick for debugging this mess.  First off the drag manager 
  9. // is not a simple animal.
  10. //
  11. // High-level or source-level debuggers won't work with Drag Manager callback routines.  
  12. // That's because of the way the Drag Manager performs process switching.  The only 
  13. // high-level debugger that does work with the Drag Manager is VoodooMonkey, an "experimental 
  14. // prototype" debugger you can find on the November Developer CD.  Note that VoodooMonkey 
  15. // is unsupported by Apple.  The other more-supportable option is to use MacsBug (or your 
  16. // favorite low-level debugger) for real-time debugging.  But since this 3d stuff will only
  17. // work on power macintosh cpu's (unless you have the souce code, which developers don't :0>)
  18. // MacsBug won't help you much.  And I was using a version of CodeWarrior that didn't seem to 
  19. // want to put any symbols in, which means Macsbug is not really an option (debugging what
  20. // MB thinks is the 68k equivalent of the actual PPC instructions, with no symbols, ain't
  21. // my idea of fun.  And don't think DebugStr will help you any - if you are running with 
  22. // the MetroWerks (MW) high level debugger, your mAchine will crash big time.  MW debugger
  23. // wants to display the debugstr in a nice little dialog, which means it has to do a context
  24. // switch.  Why is this bad... read on McDuff:
  25. //
  26. // The Drag Manager is actually making full context switches for each process that has  
  27. // tracking/receive handlers as an object is dragged over a valid drag region.  While this 
  28. // may sound a bit drastic or scary, it isn't really that bad because a drag is a modal operation,  
  29. // and as long as the user is dragging an object, the System (namely the Drag Manager) is in  
  30. // control to call tracking and receive handlers as appropriate.  So when your receive handler  
  31. // is called and all events pending for your process have been handled, your application is  
  32. // eliglble for a context switch the next time WaitNextEvent is called.  And when WNE is called  
  33. // and a context switch occurs, the Drag Manager has lost track over what process is currently  
  34. // the context.  This is also why you cannot use source-level debuggers to debug drag handlers,  
  35. // because context switches are controlled by those debuggers, and once you're in a Drag you  
  36. // cannot change the Process Manager state.
  37. //  
  38. // In case you're interested, one technique that works well for receive handlers is to send an  
  39. // Apple event to yourself with the relevant information about the drag, and process it at  
  40. // WaitNextEvent time.  Sending an Apple event to yourself can be done even if you're not the  
  41. // frontmost application, and it allows you to process the Drag at WaitNextEvent time, meaning  
  42. // you can call your Alert routine and change process states without any problems.  Another  
  43. // benefit to this approach is that you'll be able to use source level debuggers to work on  
  44. // your receive handlers.
  45. //
  46. // The only thing to beware of if you do this (and this is what do here) is to get the PSN 
  47. // directly - AppleEvents.h gives a constant (kCurrentProcess) that you can stick in the low
  48. // longword of the PSN that will cause the event to essentially be dispatched as a function
  49. // call, and that is not what we want here.  By getting the process serial number (PSN) of
  50. // our own process and using that in the AppleEvent we ensure that the event is dispatched 
  51. // to our process so we can deal with it in the main event loop, rather than being mapped into
  52. // and unwanted funtion call (which since we would still be in the drag managers context would
  53. // prevent us from being able to debug using anything reasonable).  Check out Tumbler_AEVT for
  54. // more details on this.
  55. //
  56. // Nitin Gantatra whined so much that I'd stolen the comments above, that I feel compelled to 
  57. // add:
  58. //
  59. //    Author of lame gratuitous drag manager comments: Jim Luther
  60. //
  61. //    Author:        Nick Thompson, based on the original by
  62. //                Pablo Fernicola, based on Rob Johnson's drag text sample,
  63. //                with extensive stealing from grobbins SimpleDrag sample.
  64. //
  65. //    Modification history:
  66. //
  67. //    11/26/94    nick    removed dead code, tightened up the drag code, based on
  68. //                        grobbins' excellent simpledrag sample
  69. //    11/25/94    nick    added events for dragging, this lets us do
  70. //                        source level debugging of the drag receiver, see Tumbler_aevt.
  71. //
  72. //    Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved
  73. //
  74. // to do: store the document reference as a handle in the window's refcon
  75. //
  76.  
  77.  
  78. #define NAGELS_DEMO        // pre-allocate handles
  79.  
  80.  
  81. #include <QDOffscreen.h>
  82. #include <Folders.h>
  83. #include <Drag.h>
  84. #include <SegLoad.h>
  85. #include <Types.h>
  86.  
  87. #include "Tumbler_globals.h"
  88.  
  89. #include "QD3D.h"
  90. #include "QD3DGroup.h"
  91. #include "QD3DStorage.h"
  92. #include "QD3DIO.h"
  93. #include "QD3DView.h"
  94. #include "QD3DDrawContext.h"
  95. #include "QD3DPick.h"
  96. #include "QD3DShader.h"
  97. #include "QD3DTransform.h"
  98. #include "QD3DGroup.h"
  99.  
  100. #include "Tumbler_prototypes.h"
  101. #include "Tumbler_file.h"
  102. #include "Tumbler_resources.h"
  103. #include "Tumbler_offscreen.h"
  104.  
  105.  
  106. #include "Tumbler_AEVT.h"            // grab our apleEvent handlers and data structures
  107.                                     // used for debugging
  108. #include "Tumbler_drag.h"
  109.  
  110.  
  111.  
  112. //    Can use custom drawing procedure. Just uncomment out this line:
  113. //    #define USE_CUSTOM_DRAWING
  114.  
  115.  
  116. // global data for my Drag Manager handlers
  117.  
  118. typedef struct DragHandlerGlobals 
  119. {
  120.     Boolean         acceptableDragFlag;
  121.     Boolean         windowIsHilightedFlag;
  122. } ;
  123.  
  124. typedef struct DragHandlerGlobals
  125.     DragHandlerGlobals, *DragHandlerGlobalsPtr;
  126.  
  127. static DragHandlerGlobals pDragHandlerGlobals;
  128.  
  129.  
  130. //-----------------------------------------------------------------------
  131. //    MyDrawingProc
  132. //
  133. //    Simple drawing proc for dragging objects. This drawing procedure is very similar to
  134. //    the Drag Manager's built in drawing proc, except that it uses a solid black pattern
  135. //    to draw the region instead of using the dithered gray pattern.
  136. //
  137. // DONT USE THIS ON POWERPC as there is a quickdraw bug that leaves artifacts
  138. // everywhere (talk to Nitin Ganatra for the gory details).
  139.  
  140.  
  141. pascal OSErr MyDrawingProc(DragRegionMessage message,
  142.                            RgnHandle showRgn, Point showOrigin,
  143.                            RgnHandle hideRgn, Point hideOrigin,
  144.                            void *dragDrawingRefCon, DragReference theDragRef)
  145.  
  146. {    OSErr            result = paramErr;
  147.     RgnHandle        tempRgn;
  148.  
  149.     switch(message) {
  150.  
  151.         case dragRegionBegin:
  152.  
  153.             //
  154.             //    No initialization necessary for our drawing proc. Make sure noErr
  155.             //    is returned, otherwise the Drag Manager will revert back to it's
  156.             //    built in drawing proc.
  157.             //
  158.  
  159.             result = noErr;
  160.             break;
  161.  
  162.         case dragRegionDraw:
  163.  
  164.             //
  165.             //    Find the difference between the region needed to be shown and the
  166.             //    region needed to be hidden. Inverting the difference removes the pixels
  167.             //    that must be hidden and shows the pixels that must be shown in one step.
  168.             //
  169.  
  170.             XorRgn(showRgn, hideRgn, tempRgn = NewRgn());
  171.             InvertRgn(tempRgn);
  172.             DisposeRgn(tempRgn);
  173.             result = noErr;
  174.             break;
  175.  
  176.         case dragRegionHide:
  177.  
  178.             //
  179.             //    Simply hide the region given to us by inverting it.
  180.             //
  181.  
  182.             InvertRgn(hideRgn);
  183.             result = noErr;
  184.             break;
  185.     }
  186.  
  187.     return(result);
  188. }
  189.  
  190.  
  191.  
  192. //------------------------------------------------------------------------------------
  193. //    MySendDataProc - provides data for the drag when requested.
  194.  
  195. static pascal OSErr MySendDataProc(FlavorType theType, void *refCon,
  196.                             ItemReference theItem, DragReference theDrag)
  197.  
  198. {
  199.     DocumentPtr theDocument = (DocumentPtr ) refCon;
  200.     unsigned long    validSize;
  201.     
  202.     // so what do they want??
  203.     
  204.     if (theType == '3DMF') {
  205.  
  206.         if( theDocument->documentGroup ) {
  207.         
  208.             Handle                theData;
  209.             TQ3StorageObject        storage;
  210.             TQ3FileObject        fd;
  211.             TQ3TransformObject     xform;
  212.             TQ3GroupPosition        position;
  213.             Boolean                didAllocate = false;        // set to true if we did allocate memory
  214.             
  215.             if( Q3Object_IsType(theDocument->documentGroup, kQ3DisplayGroupTypeOrdered)) {
  216.                 Q3Group_GetFirstPositionOfType(theDocument->documentGroup, kQ3ShapeTypeTransform,&position);
  217.             } else {
  218.                 Q3Group_GetFirstPosition(theDocument->documentGroup, &position);
  219.             }
  220.  
  221.             xform = Q3MatrixTransform_New( &theDocument->modelRotation);
  222.             
  223.             position = Q3Group_AddObjectBefore(theDocument->documentGroup, position, xform);
  224.     
  225.             Q3Object_Dispose(xform);
  226.             
  227. #ifdef NAGELS_DEMO
  228.             // HO HO HO.  Actually we *do* need a way to approximate the 
  229.             // size this handle needs to be so we can preflight
  230.                         
  231.             if((theData = NewHandle(1024 * 1024 )) != nil)     {        // ask for 1M
  232.             
  233.                 MoveHHi( theData ) ;
  234.                 HLock( theData ) ;
  235.                 didAllocate = true ;
  236.                 storage = Q3HandleStorage_New( theData, GetHandleSize( theData ) );
  237.                 
  238.             }
  239.             else {
  240.             
  241.                 storage = Q3HandleStorage_New( nil, 0 );
  242.                 
  243.             }
  244. #else
  245.             storage = Q3HandleStorage_New(nil,0);
  246. #endif            
  247.             if (storage == nil)
  248.                 goto bail;
  249.             
  250.             fd = Q3File_New();
  251.             
  252.             if (fd == nil)
  253.                 goto bail;
  254.  
  255.             Q3File_SetStorage(fd, storage);
  256.                         
  257.             Tumbler_WriteScene(fd, 
  258.                                 false,
  259.                                 theDocument) ;
  260.     
  261.             Q3HandleStorage_Get(storage, &theData, &validSize);
  262.             HLock(theData);
  263.             SetDragItemFlavorData(theDrag, theItem, '3DMF', (Ptr) *theData,
  264.                                   validSize, 0L);
  265.             HUnlock(theData);
  266.             Q3Object_Dispose(storage);
  267.             Q3Object_Dispose(fd);
  268.             
  269. #ifdef NAGELS_DEMO
  270.             if( didAllocate == true ) {
  271.                 DisposHandle(theData);
  272.             }
  273. #endif
  274.  
  275.         } 
  276.         else {
  277.             return(badDragFlavorErr);
  278.         }
  279.     }  
  280.     else {
  281.  
  282.         return(badDragFlavorErr);
  283.  
  284.     }
  285.     return(noErr);
  286.     
  287. bail:
  288.     return(badDragFlavorErr);
  289. }
  290.  
  291.  
  292. //-----------------------------------------------------------------------
  293. // DragItemsAreAcceptable returns true if the contents (data) of
  294. // the drag are acceptable by a window of this application
  295. //
  296. // DragItemsAreAcceptable is called by the tracking and 
  297. // receive handlers
  298. Boolean DragItemsAreAcceptable(DragReference theDrag) ;
  299.  
  300. Boolean DragItemsAreAcceptable(DragReference theDrag)
  301. {
  302.     OSErr            retCode;
  303.     unsigned short    totalItems;
  304.     ItemReference    itemRef;
  305.     Boolean            acceptableFlag;
  306.     HFSFlavor         currHFSFlavor;
  307.     Size            flavorDataSize;
  308.     FlavorFlags        currFlavorFlags;
  309.     
  310.  
  311.     acceptableFlag = false;
  312.  
  313.     // this app can only accept the drag of a single item
  314.     retCode = CountDragItems(theDrag, &totalItems);
  315.     if (retCode == noErr && totalItems == 1) {
  316.     
  317.         // get the reference number of the dragged item
  318.         retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef);
  319.         if (retCode == noErr) {
  320.             
  321.             // use GetFlavorFlags to check on flavor existence of PICT data
  322.             // without forcing translation
  323.             
  324.             if (GetFlavorFlags (theDrag, itemRef, 'PICT', &currFlavorFlags) == noErr) {
  325.                 acceptableFlag = true;
  326.             }
  327.             else if (GetFlavorFlags (theDrag, itemRef, '3DMF', &currFlavorFlags) == noErr) {
  328.                 acceptableFlag = true;
  329.             }
  330.             else {
  331.             
  332.                 // check if the item is a file spec for a PICT file
  333.                 flavorDataSize = sizeof(HFSFlavor);
  334.                 retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &currHFSFlavor,
  335.                     &flavorDataSize, 0);
  336.                 
  337.                 if (retCode == noErr &&  (currHFSFlavor.fileType == 'PICT' 
  338.                                 || currHFSFlavor.fileType == '3DMF'
  339.                                 || currHFSFlavor.fileType == 'TEXT' )) 
  340.                     acceptableFlag = true;
  341.             }
  342.         }
  343.     }
  344.  
  345.     return acceptableFlag;
  346. }
  347.  
  348.  
  349. //-----------------------------------------------------------------------
  350. // DragIsNotInSourceWindow returns true if the drag in progress
  351. // is not in the same window it originated in
  352. //
  353. // DragIsNotInSourceWindow is called by the tracking and receive handlers
  354. //
  355. // Note that, if this application allowed items to be dragged within
  356. // its windows, this function would not be appropriate.
  357. // Instead, hilighting would probably occur in the source window
  358. // when the dragHasLeftSourceWindow flag is set, and the receive
  359. // handler wouldn't check this at all
  360.  
  361. Boolean DragIsNotInSourceWindow(DragReference theDrag)
  362. {
  363.     DragAttributes currDragFlags;
  364.     
  365.     (void) GetDragAttributes(theDrag, &currDragFlags);
  366.     return ((currDragFlags & dragInsideSenderWindow) == 0);
  367. }
  368.  
  369.  
  370. //-----------------------------------------------------------------------
  371. // MouseInContentRgn returns true if the current mouse is in the content
  372. // area of the window (but not necessarily in the visible rgn)
  373.  
  374. Boolean MouseIsInContentRgn(DragReference theDrag, WindowPtr theWindow)
  375. {
  376.     Point mousePt;
  377.     
  378.     (void) GetDragMouse(theDrag, &mousePt, nil);
  379.     return PtInRgn(mousePt, ((WindowPeek) theWindow)->contRgn);
  380. }
  381.  
  382. //-----------------------------------------------------------------------
  383. //    MyReceiveDropHandler
  384. //
  385. //    Called by the Drag Manager when a drop occurs over one of the DoDragObjects document windows.
  386.  
  387. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  388.                                   DragReference theDrag);
  389.  
  390. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  391.                                   DragReference theDrag)
  392.  
  393. {
  394.     OSErr                result;
  395.     Rect                theRect, srcRect;
  396.     unsigned short        items, index;
  397.     ItemReference        theItem;
  398.     DragAttributes        attributes;
  399.     StScrpHandle        stylHandle;
  400.     Size                dataSize, pictSize;
  401.     short                offset, selStart, selEnd, mouseDownModifiers, mouseUpModifiers, moveText;
  402.     DocumentPtr         theDocument = (DocumentPtr ) handlerRefCon;
  403.     Point                thePoint;
  404.     TQ3Object             objects = nil;
  405.  
  406.     Boolean                dataObtainedFlag;
  407.     OSErr                retCode;
  408.     
  409.     OSType                theDragFlavor ;
  410.     Point                mouseLoc ;
  411.     
  412.     
  413.     dataObtainedFlag = false;
  414.     if (!DragItemsAreAcceptable(theDrag) ||
  415.             !MouseIsInContentRgn(theDrag, theWindow) ||
  416.             !DragIsNotInSourceWindow(theDrag)) 
  417.         return dragNotAcceptedErr;
  418.                 
  419.     // We will only support one item, so get its reference number.
  420.     result = GetDragItemReferenceNumber(theDrag, 1, &theItem);
  421.     if (result != noErr)
  422.         return result;
  423.  
  424.     GetDragAttributes(theDrag, &attributes);
  425.     GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  426.     
  427.     //    Loop through all of the drag items contained in this drag
  428.     
  429.     SetRect(&theRect, 0, 0, 0, 0);
  430.  
  431.     // we ensured above that we only deal with one item being dragged to us...
  432.     
  433. //    CountDragItems(theDrag, &items);
  434.  
  435.     //    Get the item's reference, so we can refer to it.
  436.     GetDragItemReferenceNumber(theDrag, 1, &theItem);
  437.     
  438.     // get the location the user dropped the data
  439.     GetDragMouse(theDrag, &mouseLoc, nil ) ;
  440.  
  441.     //    Try to get the flags for a '3DMF' flavor. If this returns noErr,
  442.     //    then we know that a '3DMF' flavor exists in the item.
  443.  
  444.     result = GetFlavorDataSize(theDrag, theItem, '3DMF', &dataSize);
  445.     if (result == noErr) {
  446.         theDragFlavor = '3DMF' ;
  447.     }
  448.     else if((result = GetFlavorDataSize(theDrag, theItem, 'PICT', &dataSize)) == noErr) {
  449.         theDragFlavor = 'PICT' ;
  450.     } 
  451.     else {
  452.         // Couldn't get 3DMF or PICT data so try to get HFS-flavor data.
  453.         HFSFlavor        theHFSFlavor;
  454.         dataSize = sizeof(HFSFlavor);
  455.         result = GetFlavorData(theDrag, theItem, flavorTypeHFS, 
  456.                                                 &theHFSFlavor, &dataSize, 0);
  457.                                                 
  458.         if(theHFSFlavor.fileType != 'PICT' 
  459.             || theHFSFlavor.fileType != '3DMF'
  460.             || theHFSFlavor.fileType != 'TEXT' ) {
  461.             result = paramErr ;
  462.         }
  463.     }
  464.  
  465.     
  466.     // so we either have nothing or something (in the form of 3DMF or PICT data)
  467.     if (result == noErr) {
  468.         
  469.         // create a new data handle to hold the data the user just dragged in
  470.         // this needs to be the size of the data, plus the size of the 
  471.  
  472.         myPrivateDataHdl        thePrivateData = nil ;
  473.         long                    recordSize ;    
  474.  
  475.  
  476.         recordSize = sizeof( myPrivateDataRec ) ;
  477.         
  478.         // create a handle large enough for the data
  479.         thePrivateData = (myPrivateDataHdl)NewHandle( (long)(dataSize +  recordSize)) ;
  480.         
  481.         if( thePrivateData == nil )
  482.             return MemError() ;
  483.     
  484.         
  485.         (**thePrivateData).myTypeOfData = theDragFlavor ;
  486.         (**thePrivateData).myDocument = theDocument ;        // ideally we should store the doc in the windows refcon, this is hacky ???
  487.         (**thePrivateData).myDataSize = dataSize ;
  488.         (**thePrivateData).myWindow = theWindow ;
  489.         (**thePrivateData).myLocation = mouseLoc ;
  490.  
  491.         // Lock and load, I dunno if GetFlavorData moves memory, I'm just assuming it may...
  492.         
  493.         MoveHHi( (Handle)thePrivateData ) ;
  494.         HLock( (Handle)thePrivateData ) ;
  495.  
  496.         //  passing (**thePrivateData) in dereferenced - ASSUMES the hnadle is locked
  497.         GetFlavorData(theDrag, theItem, theDragFlavor, &(**thePrivateData).myData[0], &dataSize, 0L);
  498.  
  499.         HUnlock( (Handle)thePrivateData ) ;
  500.  
  501.         // package this puppy up and send it to ourselves
  502.         SendDragRecv( thePrivateData ) ;
  503.         
  504.         // and dispose of the data
  505.         DisposHandle((Handle)thePrivateData ) ;
  506.  
  507.         if (attributes & dragHasLeftSenderWindow) {
  508.             HideDragHilite(theDrag);
  509.         }
  510.     }
  511.     
  512.     return(noErr);
  513.     
  514. bail:
  515.     return(memFullErr);
  516. }
  517.  
  518.  
  519. //-----------------------------------------------------------------------
  520. //    MyTrackingHandler
  521. //
  522. //    This is the drag tracking handler for windows in the Dragging application.
  523.  
  524. pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow,
  525.                                void *handlerRefCon, DragReference theDrag);
  526.  
  527. pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow,
  528.                                void *handlerRefCon, DragReference theDrag)
  529.  
  530. {
  531.  
  532.     RgnHandle    tempRgn;
  533.     Boolean        mouseInContentFlag;
  534.     OSErr        retCode;
  535.     
  536.     retCode = noErr;
  537.     
  538.     switch (theMessage) {
  539.     
  540.         case dragTrackingEnterHandler:
  541.             
  542.             // determine if the items are acceptable and store
  543.             // that flag in the globals, plus reset the
  544.             // hilighted global flag
  545.             
  546.             pDragHandlerGlobals.acceptableDragFlag = 
  547.                 DragItemsAreAcceptable(theDrag);
  548.             pDragHandlerGlobals.windowIsHilightedFlag = false;
  549.             
  550.             // let the drag manager know if we can't accept this drag
  551.             if (!pDragHandlerGlobals.acceptableDragFlag)
  552.                 retCode = dragNotAcceptedErr;
  553.             break;
  554.             
  555.         case dragTrackingEnterWindow: 
  556.         case dragTrackingInWindow:
  557.         case dragTrackingLeaveWindow:
  558.             
  559.             // highlighting of the window during a drag is done
  560.             // here.  Do it only if we can accept these items
  561.             // and we're not in the source window...
  562.             
  563.             if (pDragHandlerGlobals.acceptableDragFlag &&
  564.                 DragIsNotInSourceWindow(theDrag)) {
  565.                 
  566.                 // unless the mouse is leaving the visible area of the
  567.                 // window, check if it's in the window's content region
  568.                 
  569.                 if (theMessage == dragTrackingLeaveWindow)
  570.                     mouseInContentFlag = false;
  571.  
  572.                 else
  573.                     mouseInContentFlag = MouseIsInContentRgn(theDrag, theWindow);
  574.                 
  575.                 // if the mouse is in the content area and the window
  576.                 // is not yet hilighted, then do the hilighting
  577.                 
  578.                 if (mouseInContentFlag &&
  579.                     !pDragHandlerGlobals.windowIsHilightedFlag) {
  580.                     
  581.                     // set the proper clip
  582.                     ClipRect(&theWindow->portRect);
  583.                     
  584.                     // make a region bordering the window content
  585.                     tempRgn = NewRgn();
  586.                     RectRgn(tempRgn, &theWindow->portRect);
  587.                     
  588.                     // draw the hilight
  589.                     if (ShowDragHilite(theDrag, tempRgn, true) == noErr) {
  590.                         // remember that hilighting is now on
  591.                         pDragHandlerGlobals.windowIsHilightedFlag = true;
  592.                     }                    
  593.                     
  594.                     // free up the region
  595.                     DisposeRgn(tempRgn);
  596.                 }
  597.                 
  598.                 // else if the mouse is not in the content region
  599.                 // and the window is hilighted, erase the hilight
  600.                 
  601.                 else if (!mouseInContentFlag &&
  602.                     pDragHandlerGlobals.windowIsHilightedFlag) {
  603.                     
  604.                     // set the proper clip
  605.                     ClipRect(&theWindow->portRect);
  606.                     
  607.                     // erase the hilight and restore the port
  608.                     if (HideDragHilite(theDrag) == noErr)
  609.                     
  610.                         // remember that hilighting is now off
  611.                         pDragHandlerGlobals.windowIsHilightedFlag = false;
  612.                 }
  613.             }
  614.             break;
  615.  
  616.         // do nothing for the leaveHandler message
  617.         case dragTrackingLeaveHandler:
  618.             break;
  619.         
  620.         // let the drag manager know if we didn't recognize the message
  621.         default:
  622.             retCode = paramErr;
  623.     }
  624.     
  625.     return retCode;
  626. }
  627.  
  628.  
  629. //
  630. //    DropLocationIsFinderTrash
  631. //
  632. //    Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  633. //
  634.  
  635. static Boolean DropLocationIsFinderTrash(AEDesc *dropLocation)
  636.  
  637. {    OSErr            result;
  638.     AEDesc            dropSpec;
  639.     FSSpec            *theSpec;
  640.     CInfoPBRec        thePB;
  641.     short            trashVRefNum;
  642.     long            trashDirID;
  643.  
  644.     //
  645.     //    Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or
  646.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  647.     //
  648.  
  649.     if ((dropLocation->descriptorType != typeNull) &&
  650.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) {
  651.  
  652.         HLock(dropSpec.dataHandle);
  653.         theSpec = (FSSpec *) *dropSpec.dataHandle;
  654.  
  655.         //
  656.         //    Get the directory ID of the given dropLocation object.
  657.         //
  658.  
  659.         thePB.dirInfo.ioCompletion = 0L;
  660.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  661.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  662.         thePB.dirInfo.ioFDirIndex = 0;
  663.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  664.  
  665.         result = PBGetCatInfo(&thePB, false);
  666.  
  667.         HUnlock(dropSpec.dataHandle);
  668.         AEDisposeDesc(&dropSpec);
  669.  
  670.         if (result != noErr)
  671.             return(false);
  672.  
  673.         //
  674.         //    If the result is not a directory, it must not be the Trash.
  675.         //
  676.  
  677.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  678.             return(false);
  679.  
  680.         //
  681.         //    Get information about the Trash folder.
  682.         //
  683.  
  684.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  685.  
  686.         //
  687.         //    If the directory ID of the dropLocation object is the same as the directory ID
  688.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  689.         //
  690.  
  691.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  692.             return(true);
  693.     }
  694.  
  695.     return(false);
  696. }
  697.  
  698.  
  699. //
  700. //    DoDragObjects
  701. //
  702. //    Drag the selected text in the given document.
  703. //
  704.  
  705. short DoDragObjects(DocumentPtr theDocument, EventRecord *theEvent, RgnHandle hiliteRgn)
  706. {
  707.     short                result;
  708.     RgnHandle            dragRegion, tempRgn;
  709.     Point                theLoc;
  710.     DragReference        theDrag;
  711.     StScrpHandle        theStyl;
  712.     AEDesc                dropLocation;
  713.     DragAttributes        attributes;
  714.     short                mouseDownModifiers, mouseUpModifiers, copyText;
  715.     unsigned long        validSize;
  716.  
  717.     if( theDocument->documentGroup ) {
  718.  
  719.         Handle                theData;
  720.         TQ3StorageObject        storage;
  721.         TQ3FileObject        fd;
  722.         TQ3GroupPosition        position;
  723.         TQ3TransformObject     xform;
  724.         
  725.         DragSendDataUPP        mySendDataProcUPP ;
  726.         
  727.         //Q3Object_Dispose(pickObject);
  728.  
  729.         CopyRgn(hiliteRgn, dragRegion = NewRgn());
  730.         SetPt(&theLoc, 0, 0);
  731.         LocalToGlobal(&theLoc);
  732.         OffsetRgn(dragRegion, theLoc.h, theLoc.v);
  733.     
  734.         //
  735.         //    Wait for the mouse to move to the mouse button to be released. If the mouse button was
  736.         //    released before the mouse moves, return false. Returing false from DoDragObjects means that
  737.         //    a drag operation did not occur.
  738.         //
  739.     
  740.         if (! WaitMouseMoved(theEvent->where)) {
  741.             return(false);
  742.         }
  743.     
  744.         // create a new reference for a track to pass to track drag
  745.         NewDrag(&theDrag);
  746.     
  747.         //    We promise '3DMF' and 'PICT'.  If a receiver requests either, the Drag Manager
  748.         //    will call our MySendDataProc to provide the data at drop time. The MySendDataProc
  749.         //    is specified by calling SetDragSendProc.
  750.         AddDragItemFlavor(theDrag, 1, '3DMF', nil, 0L, 0L);
  751. //        AddDragItemFlavor(theDrag, 1, 'PICT', nil, 0L, 0L);
  752.         
  753.         mySendDataProcUPP = NewDragSendDataProc(MySendDataProc) ;
  754.         SetDragSendProc(theDrag, mySendDataProcUPP, (void *) theDocument);
  755.     
  756.         //    Set the item's bounding rectangle in global coordinates.
  757.         SetDragItemBounds(theDrag, 1, &(**dragRegion).rgnBBox);
  758.     
  759.         //    Prepare the drag region.
  760.         tempRgn = NewRgn();
  761.         CopyRgn(dragRegion, tempRgn);
  762.         InsetRgn(tempRgn, 1, 1);
  763.         DiffRgn(dragRegion, tempRgn, dragRegion);
  764.         DisposeRgn(tempRgn);
  765.     
  766.         // on PPC the drawing proc leaves artifacts on the display when 
  767.         // highlighting and upon removal of highlighting for a window, so
  768.         // although I may prefer the drawing that my custom proc does, I
  769.         // just use the default.  This may be a bug in the drag manager
  770.         // or it may be us, but right now we'll just a void doing this and fix later
  771. //            SetDragDrawingProc(theDrag,NewDragDrawingProc(MyDrawingProc), 0L);
  772.     
  773.         //    Drag the stuff. TrackDrag will return userCanceledErr if the drop zoomed-back
  774.         //    for any reason.
  775.         result = TrackDrag(theDrag, theEvent, dragRegion);
  776.         
  777.         // get rid of the UPP
  778.         DisposeRoutineDescriptor( mySendDataProcUPP ) ;
  779.     
  780.         if (result != noErr && result != userCanceledErr) {
  781.             return(true);
  782.         }
  783.     
  784.         //    Check to see if the drop occurred in the Finder's Trash. If the drop occurred
  785.         //    in the Finder's Trash and a copy operation wasn't specified, delete the
  786.         //    source selection. Note that we can continute to get the attributes, drop location
  787.         //    modifiers, etc. of the drag until we dispose of it using DisposeDrag.
  788.         GetDragAttributes(theDrag, &attributes);
  789.         if (!(attributes & dragInsideSenderApplication)) {
  790.     
  791.             GetDropLocation(theDrag, &dropLocation);
  792.     
  793.             GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  794.             copyText = (mouseDownModifiers | mouseUpModifiers) & optionKey;
  795.     
  796.             if ((!copyText) && (DropLocationIsFinderTrash(&dropLocation))) {
  797.                 theDocument->dirty = true;
  798.                 Q3Object_Dispose(theDocument->documentGroup);
  799.                 theDocument->documentGroup = nil;
  800.             }
  801.     
  802.             AEDisposeDesc(&dropLocation);
  803.         }
  804.  
  805.         //    Dispose of the drag.
  806.         DisposeDrag(theDrag);
  807.         DisposeRgn(dragRegion);
  808.         return(true);
  809.     }
  810. bail:
  811.     return(false);
  812. }
  813.  
  814.  
  815.  
  816.  
  817.